#include "gtest/gtest.h"
#include "helper/util/NotificationCategory.h"
#include "helper/unittest/Tracer.h"

namespace test {
namespace notification {

class IObserver {
public:
    virtual ~IObserver(){}
    virtual int update(){
        TRACER.operation("IObserver-update");
        return 0;
    } 
};

} //end of namespace notification
} //end of namespace test

using namespace helper;
using namespace util;

using test::notification::IObserver;

class NotificationCategoryTest : public testing::Test {
public:
};

TEST_F(NotificationCategoryTest, testExactlyNotification){
    IObserver obs;
    ExactlyNotification<IObserver> notify;
    ASSERT_TRUE(notify.attach(&obs));
    ASSERT_EQ(1u, notify.size());

    EXPECT.reset().operation("IObserver-update");
    TRACER.reset();
    notify.visit([&](IObserver * o) -> int {
        if(o != nullptr)
            return o->update();
        return -1;
    });
    ASSERT_EQ(EXPECT, TRACER);

    notify.detach(&obs);
    ASSERT_EQ(0u, notify.size());
}

enum EventAspect {
    Plain = 0,
    Complex,
};
TEST_F(NotificationCategoryTest, testAspectNotification){
    IObserver obs;

    AspectNotification<IObserver, EventAspect> notify;
    ASSERT_TRUE(notify.attach(&obs, EventAspect::Plain));
    ASSERT_EQ(1u, notify.size(EventAspect::Plain));
    ASSERT_EQ(0u, notify.size(EventAspect::Complex));

    EXPECT.reset().operation("IObserver-update");
    TRACER.reset();
    notify.visit([&](IObserver * o) -> int {
        if(o != nullptr)
            return o->update();
        return -1;
    }, EventAspect::Plain);

		//TODO: add new visit(k, o) test case
    ASSERT_EQ(EXPECT, TRACER);

    ASSERT_TRUE(notify.detach(&obs, EventAspect::Plain));
    ASSERT_EQ(0u, notify.size(EventAspect::Plain));
}

TEST_F(NotificationCategoryTest, testKeyValueNotification){
//TODO:
}
